/**
 * 
 */
package com.amkai.aes.webservice.binary.objecthandler;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.amkai.aes.aescommon.dictionary.SharedDictionaryManagerCommon;
import com.amkai.aes.aescommon.itemprovider.ActiveStatus;
import com.amkai.aes.aescommon.service.binary.job.GeneralJob;
import com.amkai.aes.aescommon.service.result.GeneralResult;
import com.amkai.aes.aescommon.service.search.ItemEditorSearchParameter;
import com.amkai.aes.aescommon.utilities.BeanFormatter;
import com.amkai.aes.aescommon.utilities.PatientUtils;
import com.amkai.aes.generatedbeans.billinggroup.BillingGroup;
import com.amkai.aes.generatedbeans.billinggroup.BillingGroupInsurance;
import com.amkai.aes.generatedbeans.billingledger.Charge;
import com.amkai.aes.generatedbeans.dictionary.Item;
import com.amkai.aes.generatedbeans.dictionary.ItemStateCode;
import com.amkai.aes.generatedbeans.organization.BaseOrganization;
import com.amkai.aes.generatedbeans.organization.Department;
import com.amkai.aes.generatedbeans.physstaff.Physician;
import com.amkai.aes.generatedbeans.pmcase.PmCase;
import com.amkai.aes.generatedbeans.registration.Patient;
import com.amkai.aes.generatedbeans.registration.Person;
import com.amkai.aes.generatedbeans.scheduling.AbstractAppointment;
import com.amkai.aes.generatedbeans.scheduling.AppointmentRelation;
import com.amkai.aes.generatedbeans.superbill.content.AssignedDiagnosis;
import com.amkai.aes.generatedbeans.superbill.content.Assignment;
import com.amkai.aes.generatedbeans.superbill.content.Recall;
import com.amkai.aes.generatedbeans.superbill.content.SuperBill;
import com.amkai.aes.generatedbeans.superbill.content.SuperBillGroup;
import com.amkai.aes.server.util.AesServerUtils;
import com.amkai.aes.webservice.binary.JobObjectHandler;
import com.amkai.common.extensions.hibernate.config.SiteManager;
import com.amkai.common.extensions.hibernate.config.manager.SessionManager;
import com.amkai.rad.designerbase.beans.ChangedKind;

/**
 * @author petrus
 * 
 */
public class GeneralHandler implements
		JobObjectHandler<GeneralJob, Serializable, GeneralResult> {

	private static final Log log = LogFactory.getLog(GeneralHandler.class);

	
	public GeneralResult process(GeneralJob job, Serializable object)
			throws Exception {
		GeneralResult result = new GeneralResult();
		switch (job.kind) {
		case SAVE_SUPERBILL:
			result.resultId = saveSuperBill(job).getId();
			break;
		case PHYSICIAN_FROM_ID:
			result.physician = getPhysicianFromId(job.objectId);
			break;
		case GET_PATIENT_FROM_PERSON:
			result.patient = getPatientFromPerson(job.objectId);
			break;
		case SET_THE_ONE_PMCASE_DOS_TO_FIRST_APPOINTMENT:
			result.pmCaseWithEmptyAppointments = getTheOnePmCaseWithEmptyAppointments(job.getModuleDepartment(), job.objectId);
			break;
		case GET_PATIENT_CASES_WITH_RELATED_APPOINTMENTS:
			result.patientCasesWithRelatedAppointments = getPatientCasesWithRelatedAppointments(job.getModuleDepartment(), job.objectId);
			break;
		case ITEM_OF_THE_SAME_DEPARTMENT:
			result.resultItem = getItemOfTheSameDepartment(job.baseOrgId, job.objectId);
			break;
		case RELOAD_DEPARTMENT:
			result.resultDepartment = getDepartment(job.objectId, job.fullFeatured);
			break;
		case GET_STATE_CODES_OF_ITEM:
			result.resultItemsWithStateCodes = getItemsWithStateCodes(job.itemEditorSearchParameter, job.getModuleDepartment());
			break;
		}
		return result;
	}

	private Physician getPhysicianFromId(long targetId) throws Exception {
		Physician result = null;
		SessionManager sm = SiteManager.Start();
		sm.openSession();
		try {
			result = sm.get(Physician.class, targetId);
			if (result != null) {
				result.getHibernateSafeClass();
				result.getName();
			}
		} catch ( Exception ex ) {
			sm.rollbackTransaction();
			log.error("", ex);
			throw ex;
		} finally {
			sm.closeSession();
		}
		return result;
	}
	private Patient getPatientFromPerson(long targetId) throws Exception {
		Person person = null;
		Patient patient = null;
		SessionManager sm = SiteManager.Start();
		sm.openSession();
		try {
			person = sm.get(Person.class, targetId);
			patient = person.getPatients().isEmpty()?null:person.getPatients().iterator().next();
			
		} catch ( Exception ex ) {
			sm.rollbackTransaction();
			log.error("", ex);
			throw ex;
		} finally {
			sm.closeSession();
		}
		return patient;
	}

	@Deprecated
	private SuperBill saveSuperBill(GeneralJob job) throws Exception {
		SessionManager sm = SiteManager.Start();
		List<Assignment> deletedAssignments = new ArrayList<Assignment>();
		sm.openSession();
		try {
			try {

				sm.openTransaction();
				Set<Assignment> as = job.superBill.getAssignments();
				// First time U have to delete the unused Assignments and
				// contained AssignedDiagnoses
				assignmentMerger(as);
				if (as != null) {
					for (Assignment a : as) {
						if (a.getChangedKind() == ChangedKind.DELETED) {
							Set<AssignedDiagnosis> ads = a.getAssignedDiagnosises();
							log.debug("Assignment ChangedKind: "+ a.getChangedKind());
							if (ads != null) {
								for (AssignedDiagnosis ad : ads) {
									log.debug("AssignedDiagnoses ChangedKind: "+ ad.getChangedKind());
									log.debug(ad.getAssignment());
									sm.saveRAD(ad);
								}

							}
							deletedAssignments.add(a);
							sm.saveRAD(a);

						}

					}
				}
				if (!deletedAssignments.isEmpty()) {
					for (Assignment assignment : deletedAssignments) {
						job.superBill.removeAssignment(assignment);
					}
					job.superBill.setAssignmentsChanged();
					job.superBill.setChangedKind(ChangedKind.CHANGED);
					// sm.closeSession();
					// sm.openSession();
				}
				sm.commitTransaction();
			} catch (Exception e) {
				sm.rollbackTransaction();
				log.error("", e);
				throw e;
			}

			try {
				sm.openTransaction();
				PmCase pc = job.superBill.getPmcase();
				if (pc != null) {
					log.debug("PmCase ChangedKind: "+ pc.getChangedKind());
					sm.saveRAD(pc);
				}
				
				Recall rc = job.superBill.getRecall();
				if (rc != null) {
					log.debug("ReCall ChangedKind: "+ rc.getChangedKind());
					sm.saveRAD(rc);
				}

				log.debug("SuperBill ChangedKind: "+ job.superBill.getChangedKind());
				sm.saveRAD(job.superBill);
				
				Set<SuperBillGroup> sbgs = job.superBill.getSuperBillGroups();
				if (sbgs != null) {
					for (SuperBillGroup sbg : sbgs) {
						log.debug("Super Bill Group ChangedKind: "+ sbg.getChangedKind());
						sm.saveRAD(sbg);
					}
				}

				Set<Assignment> as = job.superBill.getAssignments();
				if (as != null) {
					for (Assignment a : as) {
						log.debug("Assignment ChangedKind: "+ a.getChangedKind());
						if (a.getChangedKind() == ChangedKind.CREATED) {
							Set<AssignedDiagnosis> ads = a.getAssignedDiagnosises();
							a.setChangedKind(ChangedKind.CREATED);
							sm.saveRAD(a);
							if (ads != null) {
								for (AssignedDiagnosis ad : ads) {
									log.debug("AssignedDiagnoses ChangedKind: "+ ad.getChangedKind());
									sm.saveRAD(ad);
								}
							}

						}

					}
				}

				sm.commitTransaction();
			} catch (Exception e) {
				sm.rollbackTransaction();
				log.error("", e);
				throw e;
			}
		} catch (Exception e) {
			sm.rollbackTransaction();
			log.error("",e);
			throw e;
		} finally {
			sm.closeSession();
		}
		return job.superBill;
	}

	private void assignmentMerger(Set<Assignment> assignments){
		Map<Long, Charge> deletedAssignmentCharges = new HashMap<Long, Charge>(); 
		for(Assignment as : assignments){
			if (as.getChangedKind() == ChangedKind.DELETED && as.getCharge() != null){
				deletedAssignmentCharges.put(as.getProcedure().getId(), as.getCharge());
				as.setCharge(null);
			}
		}
		for(Assignment as : assignments){
			if (as.getChangedKind() == ChangedKind.CREATED){
				Charge chargeFromDelete = deletedAssignmentCharges.get(as.getProcedure().getId());
				if (chargeFromDelete != null){
					as.setCharge(chargeFromDelete);
				}
			}
		}
	}
	private PmCase getTheOnePmCaseWithEmptyAppointments(Department dep, long id) {
		PmCase result = null;
		SessionManager sm = null;
		try {
			sm = SiteManager.Start();
			sm.openSession();

			result = sm.get(PmCase.class, id);
			// Ha a Patient-hez tobb case tartozik, akkor nem allitjuk default a
			// case DOS-jat az appointment-ekhez, ezert adunk vissza ebben az esetben
			// null-t:
			if (result == null ||
					PatientUtils.getPmCaseCount(result.getPatient(), dep) != 1) {
				return null;
			}
			result.getHibernateSafeClass();

			/*ArrayList<AbstractAppointment> aas = new ArrayList<AbstractAppointment>(result.getAbstractAppointments());
			AbstractAppointment minApp = Collections.min(aas, new Comparator<AbstractAppointment>() {
				@Override
				public int compare(AbstractAppointment arg0, AbstractAppointment arg1) {
					return arg0.getBeginTime().compareTo(arg1.getBeginTime());
				}
			});*/
			//SchedulerSharedUtils.setCaseDOS(result, minApp);
		} catch ( Exception ex ) {
			log.error("", ex);
			throw new RuntimeException(ex);
		} finally {
			if (sm != null)
				sm.closeSession();
		}
		return result;
	}
	private Set<PmCase> getPatientCasesWithRelatedAppointments(Department dep, long patientId) {
		SessionManager sm = null;
		try {
			sm = SiteManager.Start();
			sm.openSession();

			Patient patient = sm.get(Patient.class, patientId);
			Set<PmCase> pmcs = PatientUtils.getPmCases(patient, dep);
			for (PmCase pmCase : pmcs) {
				processLazyCase(pmCase);
				for (PmCase ascCase : pmCase.getAssociatedCases()) {
					processLazyCase(ascCase);
				}
				for (AbstractAppointment aa : pmCase.getAbstractAppointments()) {
					processLazyAppointment(aa);
				}
			}
			return pmcs;
		} catch ( Exception ex ) {
			log.error("", ex);
			throw new RuntimeException(ex);
		} finally {
			if (sm != null)
				sm.closeSession();
		}
	}
	private void processLazyCase(PmCase pmCase) {
		pmCase.getDescription();
		for (BillingGroup bg : pmCase.getBillingGroups()) {
			for(BillingGroupInsurance bgi : bg.getBillingGroupInsurances()) {
				if (bgi.getSequence() == 1) {
					bgi.getInsurancePolicy().getInsuranceClaimOffice().getInsuranceCarrier();
					break;
				}
			}
		}
	}

	private void processLazyAppointment(AbstractAppointment aa) {
		aa.getBeginTime();
		aa.getAppointmentType().getName();
		for (AppointmentRelation ar : aa.getRelatedAppointments()) {
			ar.getKind();
			if (ar.getTargetAppointment() != null) {
				processLazyAppointment(ar.getTargetAppointment());
			}
		}
	}

	private Item getItemOfTheSameDepartment(long baseOrgId, long id) throws Exception {
		SessionManager sm = SiteManager.Start();
		sm.openSession();
		try {
			Item r = AesServerUtils.getSharedItemPairFromDepartment(sm, sm.get(Item.class, id), sm.get(BaseOrganization.class, baseOrgId));
			if (r != null)
				r.getHibernateSafeClass();
			BeanFormatter.formatReference(r);
			return r;
		} catch ( Exception ex ) {
			ex.printStackTrace();
			log.error("", ex);
			throw ex;
		} finally {
			if (sm != null)
				sm.closeSession();
		}
		
	}
	@SuppressWarnings("unchecked")
	private List<Item> getItemsWithStateCodes(ItemEditorSearchParameter itemEditorSearchParameter, Department moduleDepartment) throws Exception {
		SessionManager sm = SiteManager.Start();
		sm.openSession();
		try {
			String act = "";
			// KKORNEL: AES-10401
			if (itemEditorSearchParameter.getActiveStatus() == ActiveStatus.ACTIVE)
				act = " AND itm.active=true";
			else if (itemEditorSearchParameter.getActiveStatus() == ActiveStatus.INACTIVE)
				act = " AND itm.active=false";
			// KKORNEL: AES-11533
			List<Item> items = sm.execute(
						"FROM "+
						SharedDictionaryManagerCommon.getInstance().getItemClass(itemEditorSearchParameter.getItemKind()).getName()+
						" itm WHERE itm.baseOrganization IN (1,"+moduleDepartment.getId()+")"+
						act+" AND "+
						" itm.itemStateCodes is not empty"
					   ).list() ;
			for (Item item : items) {
				for (ItemStateCode isc : item.getItemStateCodes()) {
					if (isc.getState() != null)
						isc.getState().getName();
					isc.getCode();
				}
			}
			return items;
		} catch ( Exception ex ) {
			ex.printStackTrace();
			log.error("", ex);
			throw ex;
		} finally {
			if (sm != null)
				sm.closeSession();
		}
	}

	private Department getDepartment(Long id, boolean full) throws Exception {
		SessionManager sm = SiteManager.Start();
		sm.openSession();
		try {
			Department d = sm.get(Department.class, id);
			if (full) {
				// KKORNEL: AES-13304
				LoginHandler.browseDepartment(null, sm, d);
			}
			else if (d.getMainOffice() != null)
				d.getMainOffice().equals(null);
			d.getHibernateSafeClass();
			return d;
		} catch ( Exception ex ) {
			ex.printStackTrace();
			log.error("", ex);
			throw ex;
		} finally {
			if (sm != null)
				sm.closeSession();
		}
		
	}
}
